home *** CD-ROM | disk | FTP | other *** search
- /*
- HASDialogs.c from Hsoi's App Shell. © 1995-1997 John C. Daub. All rights reserved.
-
- This file contains the "big" functions for dealing with most every dialog box in
- the shell: modal, modeless, movable modal, about, splash, registration, etc.
- (the help dialog box, cool about box (the funky animated scrolling credits thing),
- preferences, etc. are covered in their own files).
-
- Utility functions for dialogs (pretty much code that's more easily reusable than
- these functions) can be foundin HASUtilDialogs.c
-
- Lots of the stuff in here are derrived, gleaned from, adapted from, based upon,
- (whatever) stuff from books (like Scott Knaser's "Macintosh Programming Secrets"
- 2nd ed.) and stuff off the net and from Apple DTS code snippets (like the Modal
- dialog)
- */
-
- #pragma mark ••• #includes •••
-
- #ifndef _WASTE_
- #include "WASTE.h"
- #endif
- #include "HASGlobals.h"
- #ifndef __HSOIS_APP_SHELL__
- #include "HASMain.h"
- #endif
- #include "HASMovableModal.h"
- #include "HASDialogs.h"
- #include "HASMenus.h"
- #include "HASUtilDialogs.h"
- #include "HASWindows.h"
- #include "HASUtilities.h"
- #include "HASUtilPStrings.h"
- #include "HASUtilCursors.h"
-
- #include "WASTE_Objects.h"
-
- #ifndef __DIALOGS__
- #include <Dialogs.h>
- #endif
- #ifndef __ICONS__
- #include <Icons.h>
- #endif
- #ifndef __SOUND__
- #include <Sound.h>
- #endif
- #ifndef __SPEECH__
- #include <Speech.h>
- #endif
-
- #pragma mark -
- #pragma mark ••• Globals and constants •••
-
- // The following globals are for the movable modal dialog/progress bar stuff
-
- GrafPtr pProgressPort;
- Rect pRect;
- long pMax;
- long pCurrent;
- long pLastCurrent;
- short pLastBorder;
-
- static const RGBColor kMMBlack = {0x0000, 0x0000, 0x0000};
- static const RGBColor kMMWhite = {0xFFFF, 0xFFFF, 0xFFFF};
- static const RGBColor kMMDarkGrey = {0x4444, 0x4444, 0x4444};
- static const RGBColor kMMSteelBlue = {0xCCCC, 0xCCCC, 0xFFFF};
-
- #pragma mark -
- #pragma mark ••• Misc Dialog Boxes •••
-
-
- /*
- * let's do the regular old about box
- */
-
-
- void HsoiDoAboutBox( void )
- {
- short itemHit;
- unsigned short randNum;
- long range;
- short resID;
- SndListHandle sndHandle;
- VersRecHndl version;
- StringHandle appName;
- DialogRef aboutBox;
- Handle iHandle;
- GrafPtr oldPort;
- ModalFilterUPP aboutBoxFilter = nil;
- Size handleSize;
-
- // if we have a sound playing, stop it before we proceed
-
- if ( SoundIsPlaying() )
- StopCurrentSound();
-
- // we have a bunch of information to get from the application to put
- // into the about box...so, let's get it all!
-
- // first, the app name.
-
- // appName = (StringHandle)GetResource( 'STR ', strAppNameString );
- // DetachResource( (Handle)appName );
- // HLock( (Handle)appName );
-
- // get the app name from a 'STR ' resource
-
- appName = GetString( strAppNameString );
-
- // since we will be manipulating the data as a Pascal string, we ought to
- // make sure we expand the storage potential to it's maximum size (this is
- // something I gleaned from THINK Reference since the size of the storage
- // for the returned handled is based on the actual size of the string,
- // as indicated by its length byte).
-
- // also, according to IM:Memory, SetHandleSize might need to move the handle
- // around in memory in order to resize it. so, we need to make sure the
- // handle is unlocked before we call.
-
- HUnlock( (Handle)appName );
-
- handleSize = sizeof( Str255 );
- SetHandleSize( (Handle)appName, handleSize );
-
- // detach the resource (turn a resource handle into a regular handle)
-
- DetachResource( (Handle)appName );
-
- // and lock it down
-
- HLock( (Handle)appName );
-
- // now get the version number
-
- version = (VersRecHndl)GetResource( 'vers', 1 );
- DetachResource( (Handle)version );
- HLock( (Handle)version );
-
- // since we have to combine the app name and the version string, let's do so.
-
- HsoiConcatString( *appName, "\p " ); // need to stick a space in there so the
- // words don't run together
- HsoiConcatString( *appName, (*version)->shortVersion );
-
- // and the copyright info will just be from a macro
- // and the user name and organization we just get from the prefs
-
- // now, let's get the dialog
-
- aboutBox = GetNewDialog( rAboutBoxDLOG, nil, MOVE_TO_FRONT );
-
- // if we didn't get it, just beep and return
-
- if ( aboutBox == nil )
- {
- SysBeep(5);
- goto exit;
- }
-
- // set the port
-
- GetPort( &oldPort );
- SetGrafPortOfDialog( aboutBox );
-
- // now, set the static text items to what they should be
-
- iHandle = HsoiGetDialogItemHandle( aboutBox, iAboutBoxAppName );
- SetDialogItemText( iHandle, *appName );
-
- // fyi: there is a Str255 in the 'vers' record that you COULD use for this
- // (in the VersRec in UnivHeaders 2.1f, the struct member name is "reserved")
- // but since it's reserved and some packed info, best not to for now.
-
- iHandle = HsoiGetDialogItemHandle( aboutBox, iAboutBoxCopyright );
- SetDialogItemText( iHandle, APP_COPYRIGHT );
-
- iHandle = HsoiGetDialogItemHandle( aboutBox, iAboutBoxUser );
- SetDialogItemText( iHandle, gMyPrefs.userName );
-
- iHandle = HsoiGetDialogItemHandle( aboutBox, iAboutBoxOrg );
- SetDialogItemText( iHandle, gMyPrefs.userOrg );
-
- // since we're going to use the standard dialog filter, we usually don't
- // need to call such things as SetDialogCancelItem(). however, since
- // item #2 in this dialog is NOT a button, we'll call it ourselves to
- // allow the ok button to also double as the cancel button (this way, you
- // could press return and/or esc to dismiss the dialog)
-
- SetDialogCancelItem( aboutBox, ok );
-
-
- // now, initialize the random number generator
-
- GetDateTime( (unsigned long *)&qd.randSeed );
-
- // get the valid range of numbers. we have 4 "valid" sounds in the resource file
- // (5000 - 5003), so that's the range ( 5003 - 5000 + 1 = 4 )
-
- range = kAboutSoundMax - kAboutSoundMin + 1;
-
- // get a random number
- // the do-while loop really isn't necessary, but just to guard against some strange
- // case, this'll happen at least once, but go again if the resID happens to be out
- // of range.
-
- do
- {
- randNum = Random();
-
-
- // and now to find the valid 'snd ' resource ID number
- // this'll give a number between 0 and 3 inclusive
-
- resID = ( randNum * range ) / 65536;
- } while( (resID < 0) || (resID > range) );
-
- resID += 5000; // add 5000 to it to get the res id number
-
- // get that sound's handle
-
- sndHandle = (SndListHandle)GetResource( TYPE_SOUND, resID );
-
- // make sure we got it. if so, play it, then axe it
-
- if ( sndHandle != nil )
- {
- HLock( (Handle)sndHandle );
- SndPlay( nil, sndHandle, true );
- HUnlock( (Handle)sndHandle );
- HsoiForgetResource( (Handle *)&sndHandle );
- }
-
- // display the about box
-
-
- ShowWindow( GetDialogWindow( aboutBox ) );
-
- // make a happy cursor
-
- InitCursor();
-
- // kick into ModalDialog until they leave
-
- aboutBoxFilter = HsoiGetMyStandardDialogFilter();
-
- do {
- ModalDialog( aboutBoxFilter, &itemHit );
-
- // this is just to be a smart-ass ;)
-
- if ( (itemHit == iAboutBoxIcon) && gHasSpeechManager )
- {
- SpeakString( "\pWhat, did you think clicking on the icon would do something special?" );
- while ( SpeechBusy() != nil )
- ;
- }
-
- } while ( (itemHit != ok) && (itemHit != cancel) );
-
-
- exit:
-
- if ( aboutBoxFilter != nil )
- DisposeRoutineDescriptor( aboutBoxFilter );
-
- if ( appName != nil )
- {
- HUnlock( (Handle)appName );
- // HsoiForgetResource( (Handle *)&appName );
- HsoiForgetHandle( (Handle *)&appName );
- }
-
- if ( version != nil )
- {
- HUnlock( (Handle)version );
- // HsoiForgetResource( (Handle *)&version );
- HsoiForgetHandle( (Handle *)&version );
- }
-
- if ( aboutBox != nil )
- DisposeDialog( aboutBox );
-
- SetPort( oldPort );
-
- // and that's all she wrote....boring? i know...
-
- return;
- }
-
-
- /*
- * this does our splash screen.
- */
-
- // normally, you don't want strings to be hard coded like this (for localization). but in
- // this one case, we're gonna make an exception.
-
- Boolean HsoiDoSplashScreen( void )
- {
- GrafPtr oldPort;
- DialogRef splashDialog;
- RGBColor oldForeColor;
- Rect logoRect;
- short dialogWidth,
- dialogCenter,
- strWidth,
- halfStrWidth,
- offset;
- Point currentPosition;
- FontInfo theFontInfo;
- register short lineHeight;
- Str255 text;
- PicHandle logoPICT;
- Boolean weSpoke;
- long waitTicks;
- EventRecord event;
-
-
- // get the dialog box
-
- splashDialog = GetNewDialog( rSplashScreen, nil, MOVE_TO_FRONT );
-
- // if we didn't get a dialog box, we'll just skip the whole splash screen affair
-
- if ( splashDialog == nil )
- return false;
-
- // let's try to get the logo pict. if we don't get it, skip it all.
-
- logoPICT = GetPicture( rLogoPICT );
- if ( logoPICT == nil )
- {
- DisposeDialog( splashDialog );
- return false;
- }
-
- // ok, we got our stuff, let's set the current drawing/graphics port to the dialog.
-
- GetPort( &oldPort );
- SetGrafPortOfDialog( splashDialog );
-
- // set the cursor to an arrow (cause who knows what it'll be otherwise)
-
- InitCursor();
-
- // reset the drawing pen
-
- PenNormal();
-
- // let's set the text style (boring style yes, but i can be 99.9% sure that just
- // about any Mac (with a Roman script system) will have Geneva 12 since it's burned
- // into the ROMs. Again, this is bad for localization, but i don't intend on
- // distribution (right now at least) to non-Roman systems (cause I have no way of
- // programming nor testing on any other system than my computer at home and work)
-
- TextFont( geneva );
- TextSize( 12 );
- TextMode( srcOr );
-
- // let's set the fore color (the text will appear in this color) to white, but how
- // we set it all depends on the quickdraw version available. Since we're running
- // system 7 at least, it's probably not necessary to check for this, but can't hurt.
-
- if ( gHasColorQD )
- {
- GetForeColor( &oldForeColor );
- RGBForeColor( &kMMWhite );
- }
- else
- PenPat(&qd.white);
-
- // get some measurements so we know where to draw strings..
-
- dialogWidth = GetWindowPort((WindowRef)splashDialog)->portRect.right -
- GetWindowPort((WindowRef)splashDialog)->portRect.left;
- dialogCenter = dialogWidth / 2;
-
- HsoiGetDialogItemRect( splashDialog, 1, &logoRect );
-
- // show the thing (yea, it's empty...we'll draw things as sthey happen so we don't
- // have to worry about updating the thing (hopefuly))
-
- ShowWindow( GetDialogWindow(splashDialog) );
-
- // throw in the logo
-
- DrawPicture( logoPICT, &logoRect );
-
- // Draw all the strings. All the funky calculations are to allow things to be
- // centered horizontally and spaced nicely vertically.
-
- HsoipStringCopy( APP_COPYRIGHT, text );
- strWidth = StringWidth( text );
- halfStrWidth = strWidth / 2;
- offset = dialogCenter - halfStrWidth;
- MoveTo( offset, logoRect.bottom + 20 );
- DrawString( text );
-
- GetPen( ¤tPosition );
- GetFontInfo( &theFontInfo );
- lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
-
- HsoipStringCopy( "\pRegistered to:", text );
- strWidth = StringWidth( text );
- halfStrWidth = strWidth / 2;
- offset = dialogCenter - halfStrWidth;
- MoveTo( offset, currentPosition.v + lineHeight + lineHeight ); // move down 2 lines
- DrawString( text );
-
- GetPen( ¤tPosition );
- strWidth = StringWidth( gMyPrefs.userName );
- halfStrWidth = strWidth / 2;
- offset = dialogCenter - halfStrWidth;
- MoveTo( offset, currentPosition.v + lineHeight + lineHeight );
- DrawString( gMyPrefs.userName );
-
- GetPen( ¤tPosition );
- strWidth = StringWidth( gMyPrefs.userOrg );
- halfStrWidth = strWidth / 2;
- offset = dialogCenter - halfStrWidth;
- MoveTo( offset, currentPosition.v + lineHeight );
- DrawString( gMyPrefs.userOrg );
-
- // all the strings are drawn...let's be cute and use the Speech Manager.
-
- if ( gHasSpeechManager && gMyPrefs.doStartupSpeech )
- {
- SpeakString( "\pWelcome to Hsoi's App Shell." );
- while( SpeechBusy() != nil )
- ; // do nothing, just wait until it's done speaking
- weSpoke = true;
- }
- else
- weSpoke = false;
-
- // get rid of any key and mouse events in the queue before we go..
-
- FlushEvents(mDownMask | mUpMask | keyDownMask | keyUpMask | autoKeyMask, 0);
-
- // now draw saying they can click the mouse to continue
-
- GetPen( ¤tPosition );
- HsoipStringCopy( "\p(Click mouse button to continue)", text );
- strWidth = StringWidth( text );
- halfStrWidth = strWidth / 2;
- offset = dialogCenter - halfStrWidth;
- MoveTo( offset, currentPosition.v + lineHeight + lineHeight );
- DrawString( text );
-
- // now just sit around waiting for them to click the mouse button, OR if the
- // dialog's been up for 30 seconds, dump it anyways
-
- waitTicks = TickCount() + 1800; // 1800 ticks == 30 seconds
-
- // and it's nice to keep getting events here so that it doesn't seem like
- // the computer is locked up (things in the background can continue to
- // function, etc)
-
- do {
-
- // get the next event
-
- GetNextEvent( mDownMask, &event );
-
- // give a little time to the system
-
- SystemTask();
-
- // if 30 seconds hasn't yet elapsed, keep looping, or break out
-
- if ( TickCount() <= waitTicks )
- continue;
- else
- break;
-
- // or if we got a mouseDown event, kick out
-
- } while ( event.what != mouseDown );
-
- // now, i probably could have done the above in a simpler manner...just forget all
- // the GetNextEvent stuff and call Button() to see if the button got clicked. but
- // i like this way better cause it allows stuff in the background (especially
- // a user's clock, like if there's one in the menubar) to get updated...and like
- // with the clock thing, it could allow the user to know their computer didn't freeze.
- // also, you could easily expand this to not only look for the mouse, but like if
- // you wanted to allow the user to hit the mouse or hit any key (or even a specific
- // key(s) like return and/or space bar) you could add that sort of filtering in here.
- // so, tho this is a bit more of a consuming way to do things, it could be much more
- // easily expanded and flexible, IMHO
-
- // and once again flush things so things don't click through
-
- FlushEvents(mDownMask | mUpMask | keyDownMask | keyUpMask | autoKeyMask, 0);
-
- // clean up
-
- DisposeDialog( splashDialog );
- RGBForeColor( &oldForeColor );
- SetPort( oldPort );
-
- return weSpoke;
- }
-
-
-
- /*
- This will allow the user to change the font size to just about any size they
- feel like it.
-
- Marco Piovanelli notified me that Apple wants us to allow people to change to
- font sizes up to 32,767 points. Well, i tired that and that just gets plain
- silly...you can't even see the thing (i couldn't see much after around 2000 points).
-
- So, to keep things a wee bit more practical, we'll just go up to 500 points (if
- that's still practical). But it is possible to go up to 32,767 points. If you
- want to support this much, just be sure to change the appropriate things not only
- here, but also in the filter.
-
- Speaking of Marco, to handle this dialog, i used to use a modal dialog, tho that's
- not really practical. I then tried to use my HelpModalDialog from the help stuff. That
- worked ok. But, just to show off another way to do a movable modal dialog, I'm using
- the MovableModal Library 2.0 source from Marco Piovanelli. Marco has some neat stuff
- to really make it stand alone, however there is *1* problem: i can't get the
- menus to disable and reenable properly with Marco's code. *shrug* it's not something
- I'll sweat for now (maybe you want to?). So, you'll see commented out in the code
- the places where the calls belong, but the only thing from this lib that I'm using
- is the actualy MovableModalDialog() call.
- */
-
- long HsoiDoOtherFontSize( WindowRef theWindow )
- {
- DialogRef theDialog;
- short itemHit;
- long fontSize = 12;
- Handle itemHandle;
- Str255 itemText;
- short mode = weDoAll;
- TextStyle ts;
- Boolean zeroFont = false;
- ModalFilterUPP fontSizeFilterProc = nil;
- Handle okButtonHandle;
-
- // if we have a sound playing, stop it before we proceed
-
- if ( SoundIsPlaying() )
- StopCurrentSound();
-
- // let's get our dialog. set the dialog to track the cursor movement.
- // no need to SetDialogDefaultItem() or SetDialogCancelItem() cause
- // the dialog filter handles all that.
-
- theDialog = GetNewDialog( rOtherFontSizeDialog, nil, MOVE_TO_FRONT );
- SetDialogTracksCursor( theDialog, true );
-
- // let's get our dialog filter
-
- fontSizeFilterProc = NewModalFilterProc( hsoiOtherFontSizeDialogFilter );
-
- // grab a handle to the OK button for dimming (this is a cute technique)
-
- okButtonHandle = HsoiGetDialogItemHandle( theDialog, ok );
-
- // set the number in the dialog to be whatever the current font size is
-
- WEContinuousStyle( (unsigned short *)&mode, &ts, HsoiGetWindowWE(theWindow) );
- if ((mode & weDoSize) != 0 )
- {
- NumToString( ts.tsSize, itemText );
- itemHandle = HsoiGetDialogItemHandle( theDialog, iOtherSizeSizeEditText );
- SetDialogItemText( itemHandle, itemText );
- SelectDialogItemText( theDialog, iOtherSizeSizeEditText , 0, MAXSHORT );
- }
- else // else set it to the default from the prefs
- {
- NumToString( gMyPrefs.defSize, itemText );
- itemHandle = HsoiGetDialogItemHandle( theDialog, iOtherSizeSizeEditText );
- SetDialogItemText( itemHandle, itemText );
- SelectDialogItemText( theDialog, iOtherSizeSizeEditText, 0, MAXSHORT );
- }
-
- // show the window
-
- ShowWindow( GetDialogWindow(theDialog) );
-
- // here's where the MovableModalLib from Marco would call DisableMenuBar(). If you
- // use this, make sure to comment out the following 2 lines (gInModalState and AdjustMenus)
- // Having gInModalState = true and calling HsoiAdjustMenus() does the same sorta thing
-
- // DisableMenuBar( mEdit, -1 );
-
- gInModalState = true;
- HsoiAdjustMenus();
-
- // now the fun stuff! let's do the dialog. note the funky use of a do-while loop
- // and another do-while loop nested within it. this is cause the first (nested one)
- // actually does the dialog and the second is there to make sure only kosher
- // values are entered into the dialog. nifty? you be the judge
-
- do{
-
- do {
-
- // first, we gotta make sure we have some kosher number in the dialog
-
- GetDialogItemText( itemHandle, itemText );
-
- StringToNum( itemText, &fontSize );
-
- // here we used to call ModalDialog(), but now
- // we'll just use Marco's Library to handle our movable modal dialog.
-
- MovableModalDialog( fontSizeFilterProc, &itemHit );
-
- } while ( (itemHit != ok) && (itemHit != cancel) );
-
- // ok...we've done the actual dialog stuff, now let's check for itemHits and
- // also for kosher number entry
-
- // the user can do 3 things: 1. hit OK, 2. hit CANCEL 3. enter a number.
- // don't matter much about canceling, but if they hit OK, we gotta make sure
- // things are kosher...let's do so.
-
- if ( itemHit == ok )
- {
- itemHandle = HsoiGetDialogItemHandle( theDialog, iOtherSizeSizeEditText );
- GetDialogItemText( itemHandle, itemText );
- StringToNum( itemText, &fontSize );
- zeroFont = false;
- }
- else // this is just "arbitrary" to make sure things work right
- {
- fontSize = 12; // so we don't get an "invalid size" sysbeep
- zeroFont = true;
- }
-
- // if we got an invalid size, yell at the user and have em do it again.
-
- if ( (fontSize > kMaxFontSize) || (fontSize < kMinFontSize) )
- {
- HsoiDoIllegalFontSize();
- SelectDialogItemText( theDialog, iOtherSizeSizeEditText, 0, MAXSHORT );
- }
-
- } while ( (fontSize > kMaxFontSize) || (fontSize < kMinFontSize) );
-
- // all things are good, kosher font sizes, let's clean up
-
- DisposeRoutineDescriptor( fontSizeFilterProc );
-
- DisposeDialog( theDialog );
-
- gInModalState = false;
- HsoiAdjustMenus();
-
- // and here we call ReEnableMenuBar() from Marco's MovableModalLib. If you uncomment this,
- // be sure to comment out the above 2 lines (gInModalState and HsoiAdjustMenus().
-
- // ReEnableMenuBar();
-
- if ( zeroFont )
- fontSize = 0;
-
- return fontSize;
- }
-
- /*
- * Here's the filter routine for the Other Font Size dialog.
- */
-
- // this also ought to check to see if the user attempts to paste something into the
- // dialog, cuase they might paste letters!
-
- pascal Boolean hsoiOtherFontSizeDialogFilter( DialogRef theDialog, EventRecord *event, short *item )
- {
- GrafPtr oldPort;
- char theKey;
- Boolean retval = false;
- Str255 textStr;
- Boolean okIsDimmed;
- short thePart;
- WindowRef window;
-
- // save the old graphics port and set the current one to our dialog.
-
- GetPort( &oldPort );
- SetGrafPortOfDialog( theDialog );
-
- // see if there's any text in there. if not, dim the ok button and snarf any return/enters
- // oh, if the edit text box is initially empty (like when the dialog is brought up), the
- // ok button should be but will not be dimmed (since this filter isn't called until after
- // some event happens in the dialog). But this is "worked around" by making sure that
- // the dialog has something in the edit text when the dialog is brought up.
-
- GetDialogItemText( HsoiGetDialogItemHandle( theDialog, iOtherSizeSizeEditText ), textStr );
-
- // (remember, tho we're programming in C, strings on the Macintosh are stored/used
- // in Pascal format. So, no need to call strlen() or something, just look at the
- // zero byte of the arry for the length...neat and simple
-
- if ( textStr[0] == 0 )
- {
- // no text in the field, we can't let them leave with nothing specified! dim that OK
-
- HiliteControl( (ControlRef)HsoiGetDialogItemHandle( theDialog, ok ), kCtlInactive );
- okIsDimmed = true;
- }
- else
- {
- // something's there...make sure it's not dimmed.
-
- HiliteControl( (ControlRef)HsoiGetDialogItemHandle( theDialog, ok ), kCtlActive );
- okIsDimmed = false;
- }
-
-
- // let's check for key related events.
-
- if ( (event->what == keyDown) || (event->what == autoKey) )
- {
- theKey = event->message & charCodeMask;
-
- // to snarf or not to snarf, that is the question. Well, in this case, if they
- // hit the return/enter key and the OK button is dimmed, we ought to snarf that
- // keypress
-
- if ( ((theKey == kEnterKey) || (theKey == kReturnKey)) && okIsDimmed )
- {
- retval = true;
- goto exit;
- }
- else
- {
- retval = false;
- }
-
- // and let's snarf some other things....if it's not one of a few certain keys,
- // we'll complain. The user only needs a few certain keys (numbers, return, etc)
- // to deal with this dialog...and by restricting them somewhat, it can make our
- // lives easier in ensuring that they don't enter any invalid stuff
-
- if ( !(theKey > 0x2F && theKey < 0x3A ) && // if it wasn't a number
- ( theKey != kEnterKey ) && // if it wasn't the Enter key
- ( theKey != kReturnKey ) && // if it wasn't the Return key
- ( theKey != kEscKey ) && // if it wasn't Escape
- ( theKey != kBackSpace ) && // if it wasn't backspace
- ( theKey != kDeleteKey ) && // if it wasn't the delete key
- ( theKey != kLeftArrow ) && // and all the arrow keys for easy editing
- ( theKey != kRightArrow ) &&
- ( theKey != kUpArrow ) &&
- ( theKey != kDownArrow ) )
- {
- SysBeep( 5 );
- retval = true; // we've handled it
- }
- else
- retval = false; // let the Dialog Manager handle it
- }
- // check for mouse events!
- else if ( event->what == mouseDown )
- {
- // check for mousedowns in the title bar (to allow dragging) and also for
- // mousedowns in the menubar so people can still access system menus and the apple menu
- // remember, this is a movable modal dialog box.
-
- thePart = FindWindow( event->where, &window );
-
- if ( thePart == inMenuBar )
- {
- MenuSelect( event->where );
- retval = true;
- }
-
- else if ( (window == GetDialogWindow(theDialog)) && (thePart == inDrag) )
- {
- HsoiDoDrag( event->where, GetDialogWindow(theDialog) );
- retval = true;
- }
-
- }// end: else if (mouseDown)
-
- // ok...that's about all the stuff we gotta handle, so if we didn't handle it in here,
- // we should let the standard dialog filter routines kick in to handle it
-
- exit:
- if ( !retval )
- retval = hsoiMyStandardDialogFilter( theDialog, event, item );
-
- // clean up and go bye bye
-
- SetPort( oldPort );
-
- return retval;
- }
-
- /*
- * This is just a little thing to complain to the user if they entered an
- * "illegal" font size somewhere
- */
-
- // it's pretty self explanitory as to what it does
-
- void HsoiDoIllegalFontSize( void )
- {
- Str255 minSize, maxSize;
-
- // if we have a sound playing, stop it before we proceed. any function that calls
- // this should have already stopped the sound (if any), but just in case...
-
- if ( SoundIsPlaying() )
- StopCurrentSound();
-
- NumToString( kMinFontSize, minSize );
- NumToString( kMaxFontSize, maxSize );
-
- ParamText( minSize, maxSize, NIL_STRING, NIL_STRING );
-
- StopAlert( rIllegalFontSizeAlert, HsoiGetMyStandardDialogFilter() );
-
- return;
- }
-
- #pragma mark -
- #pragma mark ••• Modal Dialog •••
-
-
- /******************************************************************************************\
- * *
- * BEGIN SECTION AND STUFF DEALING WITH MODAL DIALOGS *
- * ^^^^^ *
- * *
- * *
- \******************************************************************************************/
-
-
-
- /*
- * The base code for this modal dialog comes from an Apple DTS Snippet called "DialogBits
- * 2.0.1" by C.K. Haun. I suppose he or Apple or whomever retains rights to the original. I just
- * thought to do this cause it explains a bunch of the neat-o things and FAQ's that
- * people want to do with dialogs. It ain't perfect and probably has some bugs/shortcomings
- * but you get the point...I hope to fix those quirks sooner or later, but they're there.
- * Heck, it'd be a good exercise for you to fix them ;) If you do, please send me the
- * code changes you made so I can keep releasing improvments to the Shell (you will get
- * credits of course :) ).
- *
- * I've modified a lot of the code to get it to compile with CW (and Universal Headers)
- * and did some stuff to add in more functionality, customize, etc etc. and of course,
- * to have PowerMac happiness.
- *
- * If you're interested, I'm sure you can find the original code on
- * ftp.info.apple.com in the associated DTS/snippet's directories (can't give an exact
- * URL at this writing since Apple's ftp sites are in a state of flux as they are
- * constantly trying to perfect things)
- */
-
- void HsoiDoModalDialog( void )
- {
- DialogRef myDialog = nil;
- short itemHit = 0;
- Rect iRect;
- short iItem;
- Handle iHandle;
- Boolean tempBool;
- SndListHandle theSound;
- Str255 tempString;
- ModalFilterUPP myModalFilterProc = nil;
- UserItemUPP editLineDimmingProc = nil;
-
- // if we have a sound playing, stop it before we proceed
-
- if ( SoundIsPlaying() )
- StopCurrentSound();
-
- // get the dialog from the resource fork
-
- myDialog = GetNewDialog( rModalDialog, nil, MOVE_TO_FRONT );
-
- if ( myDialog == nil )
- return; // lame error handling, but eh...
-
-
- // have the toolbox track the cursor movement. no need to SetDialogDefault/CancelItem()
- // cause the dialog filter handles that.
-
- SetDialogTracksCursor( myDialog, true );
-
- // set up the stuff to dim an edit line
-
- // get the UPP to the procedure
-
- editLineDimmingProc = NewUserItemProc( HsoiDimEditLine );
-
- // and install it for that item
-
- HsoiSetDialogItemProc( myDialog, iDimmingBox, editLineDimmingProc );
-
- // make sure the checkbox is unchecked
-
- iHandle = HsoiGetDialogItemHandle( myDialog, iEditCheckBox );
- SetControlValue( (ControlRef)iHandle, false );
-
- // select the edit text. this is good to do cause people can start typing.
- // here there is no point, but you'll find it quite useful (to power users of
- // your software especially) to make sure text is selected.
-
- SelectDialogItemText( myDialog, iTopEditLine, 0, MAXSHORT );
-
- // again, keep making sure that stuff is cosmetically set right
-
- HideDialogItem( myDialog, iEditTextVaryItem );
-
- // set up the radio buttons
-
- gCurrentRadio = 0;
- HsoiSetRadioButton( myDialog, kRadioButtonFirst );
-
- // and now we're finally ready to show the window
-
- ShowWindow( GetDialogWindow(myDialog) );
-
- // grab the filter
-
- if ( myModalFilterProc == nil )
- myModalFilterProc = NewModalFilterProc( hsoiFilterIt );
-
- // let's do it
-
- do
- {
- // hang out until something happens...
-
- ModalDialog( myModalFilterProc, &itemHit );
-
- // something happened...let's deal with it
-
- switch (itemHit)
- {
- // smacked Homer? make him scream...
-
- case iIconItem:
- theSound = (SndListHandle)GetResource( TYPE_SOUND, rSoundIDHomer );
- if ( theSound != nil )
- {
- SndPlay( nil, theSound, false );
- HsoiForgetResource( (Handle *)&theSound );
- }
- else
- HsoiDoError( rErrorStrings, errCantLoadSound, 0, kErrGeneric );
- break;
-
-
- // do they want to make the uneditable line editable (or vice versa)?
- // if so, make it so.
-
- case iEditCheckBox:
-
- // find out if the box is checked or not
-
- iHandle = HsoiGetDialogItemHandle( myDialog, iEditCheckBox );
- tempBool = GetControlValue( (ControlRef)iHandle );
-
- // depending on what it is, make it the other since we're switching
-
- if ( tempBool == true )
- tempBool = false;
- else
- tempBool = true;
-
- // set it as such
-
- SetControlValue( (ControlRef)iHandle, tempBool );
-
- // and if disabling the line, move the user to another edit field.
-
- if ( tempBool == false )
- {
- // FYI: before Copland, in order to see which editField was
- // the active/current one, we had to do this:
-
- // if ( ( (DialogPeek)myDialog)->editField + 1 == iBottomEditLine )
-
- // but now with Copland (and accessor routines), we just call this
- // neat little function and viola! the best part is, no more need
- // to do that "+ 1" stuff
-
- if ( GetDialogKeyboardFocusItem(myDialog) == iBottomEditLine )
- SelectDialogItemText( myDialog, iTopEditLine, 0, MAXSHORT );
- }
-
- // and whatever we do, make sure the edit line cosmetically looks right
-
- GetDialogItem( myDialog, iDimmingBox, &iItem, &iHandle, &iRect );
- SetGrafPortOfDialog( myDialog );
- InvalRect( &iRect );
- break;
-
-
- case iVaryTextCheckBoxItem:
-
- // grab a handle to the check box and get it's value
-
- iHandle = HsoiGetDialogItemHandle( myDialog, iVaryTextCheckBoxItem );
- tempBool = GetControlValue( (ControlRef)iHandle );
-
- // manipulate the value a bit...
-
- tempBool = tempBool ? false : true;
-
- // and reset to a new value
-
- SetControlValue( (ControlRef)iHandle, tempBool );
-
- // now make things look right depending on the new value of
- // the checkbox
-
- if ( tempBool )
- {
- HideDialogItem( myDialog, iStatTextVaryItem );
- ShowDialogItem( myDialog, iEditTextVaryItem );
- }
- else
- {
- GetDialogItemText( HsoiGetDialogItemHandle( myDialog, iEditTextVaryItem), tempString );
- SetDialogItemText( HsoiGetDialogItemHandle( myDialog, iStatTextVaryItem), tempString );
- HideDialogItem( myDialog, iEditTextVaryItem );
- ShowDialogItem( myDialog, iStatTextVaryItem );
- }
-
- if ( tempBool )
- {
- SelectDialogItemText( myDialog, iEditTextVaryItem, 0, MAXSHORT);
- }
- else
- {
- SelectDialogItemText( myDialog, iTopEditLine, 0, MAXSHORT );
- }
-
- break;
-
- } // end switch (itemHit )
-
- // Put the radio button check here to allow for ease in expanding the number
- // of radio buttons ("if" is much easier to use than "switch"), plus,
- // for ease of implimentation if you have more than 1 group of radio buttons
- // in a dialog
-
- if ((itemHit >= kRadioButtonFirst) && (itemHit <= kRadioButtonLast ) )
- HsoiSetRadioButton( myDialog, itemHit );
-
- } while ( itemHit != ok && itemHit != cancel );
-
- // clean up
-
- DisposeRoutineDescriptor( myModalFilterProc );
- DisposeRoutineDescriptor( editLineDimmingProc );
-
- DisposeDialog( myDialog );
- InitCursor();
- HsoiAdjustMenus();
-
- return;
- }
-
- /*
- * This is the monster dialog filter routine for our big modal dialog
- */
-
- pascal Boolean hsoiFilterIt( DialogRef inputDialog, EventRecord *myDialogEvent, short *theDialogItem )
- {
- WindowRef tempWindow;
- char theKey;
- Rect tempRect;
- short tempItem;
- Handle tempHandle;
- Boolean returnVal = false;
- char tempKey;
- Str255 myStr;
- long offset;
- short selection;
- long scrapLen;
- short resultLen;
- Point mousePoint;
- Boolean hiLit = false;
- Point tempPoint;
- short thePart;
- ControlRef returnedControl;
- Boolean wasAKey = false;
- ControlActionUPP theScrollProc;
-
-
- // save the current port, and set the port to us
-
- GetPort(&(GrafPtr)tempWindow);
- SetGrafPortOfDialog(inputDialog);
-
- // Use something like this if you want to do any idle time drawing in your
- // dialog, like a clock, flashing cursor, or a classy animated icon like I'm using
-
- HsoiSpinIt(inputDialog);
-
-
- // Some key filtering schemes follow. The first is the standard filter to
- // recognize 'return' as OK and 'ESC' as cancel. What this really means
- // is that I never ever want to have to use the mouse to click the cancel
- // buttton ever again, you can just cut and paste this code from now on.
-
- // do standard filtering for escape and return as OK and Cancel aliases
- // We also invert the button in the dialog, so the user get's visual feedback
- // about the action they just took
-
- // see if the event was a key being pressed down
-
- wasAKey = (myDialogEvent->what == keyDown) || (myDialogEvent->what == autoKey);
-
- // this 'if' has a double key check because of the 'tab' key restriction
- // I'm doing. we do NOT want to pass the tab key through to the standard
- // filter, since it will tab to the other edit line even if we have it turned off
-
-
- if ( (wasAKey && ((myDialogEvent->message & charCodeMask) == kTabKey)) && wasAKey )
- {
- theKey = myDialogEvent->message & charCodeMask;
- switch (theKey)
- {
- // some of this stuff we don't need to worry about since we're using those
- // wonderful new System 7 Dialog Manager routines...it's redundant to "click"
- // the OK button when SetDialogDefaultItem() will do it for us :)
- // but let's at least make sure theDialogItem is set to the right dialog item
-
- case kReturnKey:
- case kEnterKey: // enter key
- // This filters for Return or Enter as item 1, and Esc as item 2
- *theDialogItem = ok; // change whatever the current item is to the OK item
- break;
-
- // This filters the escape key as the same as item 2 (the canx button, usually )
- case kEscKey:
- *theDialogItem = cancel;
- break;
-
- case kTabKey:
- // I'm filtering the tab key here so the user cannot tab to
- // my inactive edit line
- if (GetControlValue(HsoiSnatchHandle(inputDialog, iEditCheckBox)) == false)
- {
- returnVal = true; // don't allow edit line swaps
- }
- break;
- }
- }
-
- // Here's another kind of key filtering you need every so often, text or numeric
- // filtering. In this case, we're only going to allow non-numeric characters in
- // the second edit line we have installed in this dialog
- // Any number (1,2,3,4,5,6,7,8,9,0) will be eaten, and a beep generated
-
- /* In the original code by C.K. Haun, the number filter was only filtering out 1-8
- inclusive. 9 and 0 still got through. The "if" statement below:
-
- if ((theKey...etc
-
- used to be > 0x30 && < 0x39.
-
- I think this is the problem...i don't know keyCodes and charCodes that well, and
- the charCodeMask just makes my life better (bitvectors and manipulations on bit
- vectors (& | ^ ~) are a weak point in my programming knowledge.
-
- But, if i fanagled it right, the way it is now, > 0x2F && < 0x3A should work
- to filter out 1,2,3,4,5,6,7,8,9,0.
-
- If you find it doesn't, please notify me. John Daub.
- */
-
- if (wasAKey)
- {
- theKey = myDialogEvent->message & charCodeMask;
-
- if ((theKey > 0x2F && theKey < 0x3A) &&
- GetDialogKeyboardFocusItem(inputDialog) == iBottomEditLine)
-
- {
- // Dang, it's a number and in the wrong edit line, reject it
- SysBeep(1); // complain a little
- returnVal = true; // tell the dialog manager
- // that we handled this already and
- // it doesn't have to, so the keystroke will _not_ get
- // added to the edit line
-
- }
- }
-
- // Here's yet another kind of key filtering you need every so often.
- // I'm going to restrict the amount of text in the top edit line to just 25 characters
-
- // •• NOTE: Remember Cut/Copy/Paste!
- // Before you allow these, you need to see what the result of a Paste (in this case)
- // will be, since a Paste can also drive you over the 25 char limit.
- // I've modified the function IsEditKey to look for these
- // I've also added code that checks to see if there is a selection range,
- // since typeing one charater to replace 5 is OK
-
- // First, see if it was a key and the top edit line is active
-
- if ( wasAKey && (GetDialogKeyboardFocusItem(inputDialog) == iTopEditLine) )
- {
- selection = HsoiHasSelectionRange((DialogPeek)inputDialog);
- scrapLen = GetScrap(nil, TYPE_TEXT, &offset);
- GetDialogItem(inputDialog, iTopEditLine, &tempItem, &tempHandle, &tempRect);
- GetDialogItemText(tempHandle, myStr);
-
- // calculate the result of adding the scrap to the current record. We use
- // this in a few places here
-
- resultLen = myStr[0] + (scrapLen - selection);
- theKey = myDialogEvent->message & charCodeMask;
- tempKey = theKey;
- if (tempKey >= 0x61 && tempKey <= 0x7a)
- tempKey -= 0x20;
- if (myStr[0] > 25) // over 25, see what it is
- {
- if (HsoiIsEditKey(theKey, myDialogEvent->modifiers))
- {
- // it was an editing key, but it MAY be a command-V.
- // If it's a command-V then we won't allow it UNLESS
- // there is a slection range AND the new data won't overrun things
-
- if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey))
- {
-
- // this was a paste. check selection range and scrap len
-
- if (resultLen < 26)
- {
- returnVal = false; // net result is 25 or less
- }
- else
- {
- SysBeep(1);
- returnVal = true;
- }
- }
- else
- {
- returnVal = false; // don't filter out editing keys
- }
- }
- else
- {
- // One more check (this can get complicated, huh?)
- // We now look to see if there is a selection range. If there
- // is a range of 1 or more characters, then the one character they are entering
- // now will replace that, and we'll end up with _less_ than 25 (or equal)
- // to do this, we have to get the TERecord out of the dialog.
- // I'm going to do this in a seperate function
- if (selection == 0)
- {
- SysBeep(1); // complain a little
- returnVal = true; // tell the dialog manager that we handled this already and
- // it doesn't have to, so the keystroke will _not_ get
- // added to the edit line
- }
- }
- }
- else
- {
- // even if we're less than 25 currently, a Command-V (paste) could put us over
- // so check it out
-
- if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey)) {
-
- // Gettting the scrap with a nil handle, which does not give us data, just
- // returns the size
- if (resultLen > 25)
- {
- SysBeep(1); // complain a little
- returnVal = true; // tell the dialog manager that we handled this already and
-
- }
- }
- }
- }
-
- // We are doing three checks here in the dialog filter for mouseDown
- // events.
- // The first checks to see if we're in the icon and tracks it like a control if we are.
- // If we're not, then we may be in our scroll bar, and we have to
- // do various things if that is true.
- // Or, we may be in the disabled edit line, and we have to disallow clicks on it
- // when it's disabled
-
- if (myDialogEvent->what == mouseDown)
- {
- mousePoint = (myDialogEvent->where);
- GlobalToLocal(&mousePoint);
-
- // First see if we're in the icon
-
- GetDialogItem(inputDialog, iIconItem, &tempItem, &tempHandle, &tempRect);
- if (PtInRect(mousePoint, &tempRect)) {
-
- // invert my icon, and track it whilst the user holds the mouse down
-
- InvertRect(&tempRect);
- hiLit = true;
- while (StillDown())
- {
- GetMouse(&tempPoint); // returns point in local coords
- if (PtInRect(tempPoint, &tempRect))
- {
- // in the rect. See if it's hilighted or not
-
- if (hiLit == false)
- {
- hiLit = true;
- InvertRect(&tempRect);
- }
- }
- else
- {
- // not in the rectangle. If it's hilit, get rid of that
-
- if (hiLit == true)
- {
- hiLit = false;
- InvertRect(&tempRect);
- }
- }
- }
- if (hiLit == true)
- {
- // if it's still hilited when the mouse comes up, then that means the
- // user stayed in and wants to take this icon action
-
- InvertRect(&tempRect); // clear the hiliting if it's still lit
- *theDialogItem = iIconItem;
- returnVal = true; // telling the Dialog Manager we handled it, pass item back
- }
- }
- else
- {
- // Now see if we're in the scroll bar
-
- GetDialogItem(inputDialog, iScrollControlItem, &tempItem, &tempHandle, &tempRect);
- if (PtInRect(mousePoint, &tempRect))
- {
- // We're in the scroll bar.
- // Now, what does that mean????
- // Well, the Dialog Manager will automatically call FindControl and TrackControl
- // and set the control value (in the case of scroll thumbs)
- // on controls added to your dialog, and in many cases that's all you're going
- // to need.
- // But, ModalDialog does NOT pass back a part code, so if the userPerson
- // clicked on the thumb or arrows of the scroll bar, you won't know, you'll
- // just know that the scroll bar was clicked in
- // That's not enough, so we'll to an initial check to see where the control
- // was hit
-
- thePart = FindControl(mousePoint, inputDialog, &returnedControl);
-
- // if the hit was in an arrow or page area, we'll handle it ourselfs
-
- if (thePart != kControlIndicatorPart)
- {
- theScrollProc = NewControlActionProc( HsoiDoScrollArrows );
- TrackControl(returnedControl, mousePoint, theScrollProc );
- DisposeRoutineDescriptor( theScrollProc );
- returnVal = true;
- }
-
- // if it was in the thumb, we'll just fall through and let the Dialog Manager
- // handle it for us
-
- }
- else
- {
- // first see if we even care about this click. If the check box is true, then
- // both edit lines are active, let the dialog manager handle it
-
- if (GetControlValue(HsoiSnatchHandle(inputDialog, iEditCheckBox)))
- {
- returnVal = false; // DM will handle
- }
- else
- {
- // OK, so the edit line checkbox is NOT set, which means that we don't want
- // hits in the inactive edit line to do anything. So, see if the hit was
- // in the edit line, and report 'true' if it was, telling the Dialog Manager that
- // you handled the event and it should do nothing
-
- GetDialogItem(inputDialog, iBottomEditLine, &tempItem, &tempHandle, &tempRect);
- if (PtInRect(mousePoint, &tempRect))
- {
- returnVal = true;
- }
- else
- {
- returnVal = false;
- }
- }
- }
- }
- }
- // one final thing if we're under System 7,
- // calling the standard filter.
- // You MUST call the standard filter if you want any of the
- // new things to happen!
- // The OK button border, cursor tracking, and the rest ONLY
- // happen if you call the filter!
- // I am also only doing this if the returnValue is still false. If I have
- // set it to true somewhere in here, I don't want to call the stdFilter
-
- // Let's call our own hsoiMyStandardDialogFilter to make sure stuff in the
- // background gets updated correctly (it calls the standard dialog filter anyways)
-
- // furthermore, the above calls to the standard modal filter proc can be commented
- // out cause our filter calls it anyways...why do it twice?
-
- if ( !returnVal )
- returnVal = hsoiMyStandardDialogFilter( inputDialog, myDialogEvent, theDialogItem );
-
- return(returnVal);
- } // end filterIt
-
-
-
-
- // SpinIt animates my fancy icon
- void HsoiSpinIt(DialogRef theDialog)
- {
- static short pos;
- static long count;
- Handle myIcon;
- Rect tempRect;
- short tempItem;
- Handle tempHandle;
-
- // I'm adjusting the speed of the spin based on the value of the scroll bar
-
- if (TickCount() > count + (10 - GetControlValue(HsoiSnatchHandle(theDialog, iScrollControlItem))))
- {
- count = TickCount(); // reset count to next value
- myIcon = GetIcon(pos + rBaseSpinIcon);
-
- // you could have a rect in this function, but that'd require you to change it all
- // the time when you move the item around in your dialog. So, we'll reference it
- // from the dialog record instead
- // make sure we really got the handle
-
- if (myIcon != nil)
- {
- GetDialogItem(theDialog, iSpinItem, &tempItem, &tempHandle, &tempRect);
- PlotIcon(&tempRect, myIcon);
- HsoiForgetResource( &myIcon );
- }
- pos++;
- if (pos > 3)
- pos = 0;
- }
- } // end SpinIt
-
- // This userItem dims the bottom edit line if the check box is not checked
-
- pascal void HsoiDimEditLine(WindowRef dwind, short dinum)
- {
- ControlRef tempCont = HsoiSnatchHandle(dwind, iEditCheckBox);
-
- // only do it if the checkbox is false
-
- if (GetControlValue(tempCont) == false)
- {
- PenState thePen;
- Rect dimRect;
-
- // Save and restore the pen state so we don't mess things up for other
- // drawing routines
-
- GetPenState(&thePen);
- HsoiGetDialogItemRect( dwind, dinum, &dimRect );
- PenMode(notPatBic);
- PenPat(&qd.gray);
- PaintRect(&dimRect);
- SetPenState(&thePen);
-
- }
-
- return;
- } // end DimEditLine
-
-
- // This little routine adjusts the scroll bar during TrackControl
-
- pascal void HsoiDoScrollArrows(ControlRef theControl, short thePart)
- {
- short currentVal = GetControlValue(theControl);
- short offSet = 0;
-
- switch (thePart)
- {
- case kControlUpButtonPart:
- offSet = -1;
- break;
-
- case kControlDownButtonPart:
- offSet = 1;
- break;
-
- case kControlPageUpPart:
- offSet = -3;
- break;
-
- case kControlPageDownPart:
- offSet = 3;
- break;
-
- }
-
- // set the control value to the new one, as long as it doesn't pass limits
-
- currentVal += offSet;
- if (currentVal < 1)
- currentVal = 1;
- if (currentVal > 10)
- currentVal = 10;
- SetControlValue(theControl, currentVal);
-
- return;
-
- } // end DoScrollArrows
-
-
-
-
- /******************************************************************************************\
- * *
- * END SECTION AND STUFF DEALING WITH MODAL DIALOGS *
- * ^^^^^ *
- * *
- * *
- \******************************************************************************************/
-
-
- #pragma mark -
- #pragma mark ••• Modeless Dialog •••
-
-
- /******************************************************************************************\
- * *
- * BEGIN SECTION AND STUFF DEALING WITH MODELESS DIALOGS *
- * ^^^^^^^^ *
- * *
- * *
- \******************************************************************************************/
-
-
-
-
- /*
- * Since I don't really have a need right now to use modeless dialogs, this code
- * for all the modeless dialogs is taken straight from Knaster's MPS book (with
- * modifications to work with HAS and Copland)
- */
-
- void HsoiDoModelessDialog( void )
- {
- // if we have a sound playing, stop it before we proceed. this might be one place
- // were we don't wnat to stop a playing sound, since this is a modeless dialog.
- // but for now, we'll stop it.
-
- if ( SoundIsPlaying() )
- StopCurrentSound();
-
- // if we don't have the dialog already, get it.
-
- if ( gModelessDialog == nil )
- {
- gModelessDialog = GetNewDialog( rModelessDialog, nil, MOVE_TO_FRONT );
- }
-
- // set the dialog's windowKind for menu adjustment
-
- // SetWindowKind( GetDialogWindow( gModelessDialog ), kFindDialogKind );
-
- // show it
-
- ShowWindow( GetDialogWindow(gModelessDialog) );
- SelectWindow( GetDialogWindow(gModelessDialog) );
- SetGrafPortOfDialog( gModelessDialog );
-
- // adjust the menus to suit
-
- HsoiAdjustMenus();
-
- return;
- }
-
-
-
-
- /******************************************************************************************\
- * *
- * END SECTION AND STUFF DEALING WITH MODELESS DIALOGS *
- * ^^^^^^^^ *
- * *
- * *
- \******************************************************************************************/
-
-
- // The following function is used by both the modeless and movable modal dialogs
- // to determine if a dialog item was hit (the ok button, so dismiss the dialog)
-
- void HsoiDoDialogHit( DialogRef dlg, short item )
- {
- if ( item == ok ) // cause that's all they can hit...if you add more buttons to your dialog, you'll need to handle them appropriately
- {
- // just hide the window...don't dispose of it. this way, if the user brings it
- // up again, it'll be in the same place they last left it, stuff in the dialog
- // will be set like they left it, etc.
-
- HideWindow( GetDialogWindow(dlg) );
-
- // and if the dialog is the movable modal progress bar, make sure to reset
- // some of the globals and get things back to normal
- if ( dlg == gMovableModalDialog )
- {
- gInModalState = false;
- gPeriodicTask = false;
- SetCursor( &qd.arrow );
- HsoiAdjustMenus();
- }
- }
-
- return;
-
- }
-
-
- #pragma mark -
- #pragma mark ••• Movable Modal Dialog •••
-
- /******************************************************************************************\
- * *
- * BEGIN SECTION AND STUFF DEALING WITH MOVABLE MODAL DIALOGS *
- * ^^^^^^^^^^^^^ *
- * *
- * *
- \******************************************************************************************/
-
-
-
- /*
- * This implimentation of the movable modal dialog will do a progress bar as per
- * Knaster's MPS code.
- *
- */
-
- /* A note on successful doing of this code...
-
- I ran into problems with getting the progress bar to draw in color...it would only
- draw in black and white even tho all my code was working properly to draw color.
-
- Problem? It was my resources...
-
- The 'DLOG' resource for the movable modal (for the progress bar dialog is actually
- more appropriate) was a pure b/w resource...no color resources were attached to
- that 'DLOG' resource. I needed to have a 'dtcb' resource for that 'DLOG' resource
- (same numbers, 202 in this case) to make that dialog box a color dialog.
-
- THEN (and only then) will color happily show up in the dialog...
-
- So remember this if you run into similar situations...
-
- Thanx go to muffinhead@ins.infonet.net (MuffinHead) from Armpit Studios VII in
- Iowa City, Iowa for the help and fix :) (i owe him $2 for it) ;)
- */
-
- void HsoiDoMovableModalDialog( void )
- {
- Handle iHandle;
- Rect iRect;
- Str255 theString;
-
- // if we have a sound playing, stop it before we proceed
-
- if ( SoundIsPlaying() )
- StopCurrentSound();
-
- // if we don't have the dialog yet, get it
-
- if ( gMovableModalDialog == nil )
- {
- gMovableModalDialog = GetNewDialog( rMovableModalProgressDialog, nil, MOVE_TO_FRONT );
-
- // set the text in the dialog to tell the user what's going on.
-
- GetIndString( theString, rMovableModalStrings, strDoingLongTask );
- iHandle = HsoiGetDialogItemHandle( gMovableModalDialog, iMMProgressStaticText );
- SetDialogItemText( iHandle, theString );
- }
-
- // show the dialog
-
- ShowWindow( GetDialogWindow(gMovableModalDialog) );
- SelectWindow( GetDialogWindow(gMovableModalDialog) );
- SetGrafPortOfDialog( gMovableModalDialog );
-
- // get ready to make the progress bar update (initialize it)
-
- HsoiGetDialogItemRect( gMovableModalDialog, iMMProgressBar, &iRect );
- HsoiInitProgressIndicator( gMovableModalDialog, iRect, 500 );
-
- // set our globals
-
- gPeriodicTask = true;
- gInModalState = true;
-
- // start the cursor spinning
-
- HsoiStartManualSpinning();
-
- // adjust the menus
-
- HsoiAdjustMenus();
-
- return;
-
- }
-
- // this function sets the progress bar values to their initial values
-
- void HsoiInitProgressIndicator(GrafPtr ourPort, Rect r, long max)
- {
- pProgressPort = ourPort;
- pRect = r;
- pMax = max;
- pCurrent = 0;
- pLastCurrent = 0;
- pLastBorder = 0;
- }
-
-
- void HsoiSetProgress(long absoluteAmount)
- {
- pCurrent = absoluteAmount;
- HsoiDrawProgressBar();
- }
-
-
- Boolean HsoiSetProgressDelta(long delta)
- {
- pCurrent += delta;
- HsoiDrawProgressBar();
- return (pCurrent >= pMax);
- }
-
-
- void HsoiDrawProgressBar( void )
- {
- short border;
- short rectWidth;
-
- if ((pLastCurrent != pCurrent) && (pCurrent <= pMax)) {
- pLastCurrent = pCurrent;
- rectWidth = pRect.right - pRect.left - 2;
- border = pRect.left + 1 + rectWidth * pCurrent / pMax;
- if (pLastBorder != border) {
- pLastBorder = border;
- HsoiUpdateProgressBar();
- }
- }
- }
-
-
- void HsoiUpdateProgressBar( void )
- {
- GrafPtr oldPort;
- RGBColor oldForeColor;
- RGBColor oldBackColor;
-
- Rect doneRect;
- Rect toDoRect;
-
- doneRect = pRect;
- InsetRect(&doneRect, 1, 1);
- toDoRect = doneRect;
-
- doneRect.right = toDoRect.left = pLastBorder;
-
- GetPort(&oldPort);
- SetPort(pProgressPort);
- GetForeColor(&oldForeColor);
- GetBackColor(&oldBackColor);
- PenNormal();
-
- HsoiSetFrameColor();
- FrameRect(&pRect);
-
- HsoiSetDoneColor();
- PaintRect(&doneRect);
-
- HsoiSetToDoColor();
- PaintRect(&toDoRect);
-
- RGBForeColor(&oldForeColor);
- RGBBackColor(&oldBackColor);
- SetPort(oldPort);
- }
-
-
-
- void HsoiSetFrameColor( void )
- {
- if (gHasColorQD) {
- RGBForeColor(&kMMBlack);
- RGBBackColor(&kMMWhite);
- } else {
- PenPat(&qd.black);
- }
- }
-
- void HsoiSetDoneColor( void )
- {
- if (gHasColorQD) {
- RGBForeColor(&kMMDarkGrey);
- RGBBackColor(&kMMWhite);
- } else {
- PenPat(&qd.black);
- }
- }
-
- void HsoiSetToDoColor( void )
- {
- if (gHasColorQD) {
- RGBForeColor(&kMMSteelBlue);
- RGBBackColor(&kMMBlack);
- } else {
- PenPat(&qd.white);
- }
- }
-
-
- /******************************************************************************************\
- * *
- * END SECTION AND STUFF DEALING WITH MOVABLE MODAL DIALOGS *
- * ^^^^^^^^^^^^^ *
- * *
- * *
- \******************************************************************************************/
-
-
-